import java.io.File;
import java.io.FileWriter;
import java.io.IOException;


public class DESthread  implements Runnable{
	private int a;
	private int b;
	private int number;
	private static boolean VERBOSE = false;
	FileWriter fout;
	public DESthread(int ain, int bin, int numberin)
	{
		a = ain;
		b = bin;
		number = numberin;
	}
	public void run(){
		String plaintext = "Outsideoft";
		int[] plainbinary = rad64ToBinary(plaintext);
		String outfilename = "out" + number + ".txt";
		int[] shortkey = new int[32];
		shortkey[0] = a;
		shortkey[1] = b;
		// OVERRIDEN with guess For fine granularity prints
		shortkey = new int[] {1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,0};

		try {
			fout = new FileWriter(new File(outfilename));
		
		while (incrementKey(shortkey))
		{
			int[] mykey = buildKey(shortkey);
			if(VERBOSE)
			{
				System.out.print("Shortkey = ");
				for (int i = 0; i< 32; i++)
				{
					System.out.print(shortkey[i]);
				}
				
				//Scanner fin = new Scanner(ciphertext);
				
				System.out.print(" realkey = ");
				for(int i = 0; i<64; i++)
				{
					if(i%8 == 0)
						System.out.print(" ");
					System.out.print(mykey[i]);
				}
				System.out.println();
			}
			
			
			// Set up the keys.
			DES code = new DES(mykey, false);
			code.setKeys();
			code.setBlock(plainbinary);
			code.encrypt();
			code.print(fout);
			
			// Read in each block and process...
			/*
			while (fin.hasNext()) {
			
				String myblock = fin.next();
				if (myblock == null) break;
				int[] binblock = rad64ToBinary(myblock);
				System.out.println("Block: " + myblock);
				code.setBlock(binblock);
				code.encrypt();
				code.print(fout);
			}*/
			
			//fin.close();
		}
		fout.close();
		} catch (Exception e) {
			System.out.println(e);
			e.printStackTrace();
			
		}
	}
	
	// incoming is 10 char strings
	public static int[] rad64ToBinary(String str)
	{
		int[] bin = new int[64];
		int val = 0;
		for(int i = 0; i<10; i++)
		{
			char ch = str.charAt(i);
			if(ch >= 'A' && ch <= 'Z')
				val = ch - 'A';
			else if(ch >= 'a' && ch <= 'z')
				val = ch - 'a' + 26;
			else if(ch >= '0' && ch <= '9')
				val = ch - '0' + 52;
			else if(ch == '+')
				val = 62;
			else if(ch == '/')
				val = 63;
			else
			{
				System.out.println("Conversion error");
				System.exit(0);
			}
			for (int j=0; j<6; j++)
			{
				bin[6*i+5-j]=val%2;
				val /= 2;
			}
		}
		return bin;
	}
	
	// incoming is 10 char strings
	public static String binaryToRad64(int[] bin)
	{
		String rad64 = "";
		int val = 0;
		String temp = "";
		for(int i = 0; i<10; i++)
		{
			temp = "";
			for(int j = 0; j<6; j++)
			{
				temp += bin[6*i + j];
			}
			val = Integer.parseInt(temp, 2);
			char ch = 0;
			if(val >= 0 && val <= 25)
				ch = (char) (val + 'A');
			else if(val >= 26 && val <= 51)
				ch = (char) (val + 'a' - 26);
			else if(val >= 52 && val <= 61)
				ch = (char) (val + '0' - 52);
			else if(val == 62)
				ch = '+';
			else if(val == 63)
				ch = '/';
			else
			{
				System.out.println("Conversion error");
				System.exit(0);
			}
			rad64 = rad64 + ch;
		}
		temp = "";
		for(int j = 0; j<4; j++)
		{
			temp += bin[60 + j];
		}
		temp += "00";
		val = Integer.parseInt(temp, 2);
		char ch = 0;
		if(val >= 0 && val <= 25)
			ch = (char) (val + 'A');
		else if(val >= 26 && val <= 51)
			ch = (char) (val + 'a' - 26);
		else if(val >= 52 && val <= 61)
			ch = (char) (val + '0' - 52);
		else if(val == 62)
			ch = '+';
		else if(val == 63)
			ch = '/';
		else
		{
			System.out.println("Conversion error");
			System.exit(0);
		}
		rad64 = rad64 + ch;
		return rad64;
	}
	
	private boolean incrementKey(int[] array) throws IOException
	{
		return incrementAtIndex(array, 31);
	}
	
	private boolean incrementAtIndex(int[] array, int index) throws IOException {

        if(index == 1) // should be 1 for 2 bit threads
        {
			System.out.println("Thread number " + number + " finished checking all the keys. Check the out file and cross your fingers!");
        	return false;
		}
		// Every so often print out the shortkey in case we need to quit and restart
        else if(index == 14)
        {
        	fout.write("shortkey = ");
        	System.out.println("shortkey for thread " + number + " is: ");
        	for(int i = 0; i< 32; i++)
        	{
        		fout.write("" + array[i]);
        		System.out.print(array[i]);
        	}
        	fout.write("\n");
        	System.out.println();
        }
        if (array[index] == 1) {
            array[index] = 0;
         	return incrementAtIndex(array, index - 1);
        }
        else {
            array[index]++;
            return true;
        }
    }
	
	public static int[] buildKey(int[] small)
	{
		int[] large = new int[64];
		int parity = 0;
		for(int i = 0, j = 0; i<28; i++)
		{
			if((i+1)%7 == 0)
			{
				// Set this row's seventh bit
				large[j+i] = small[i];
				j++;
				// Set this one's parity bit
				if((parity + small[i])%2 == 0)
					large[j+i] = 1;
				else
					large[j+i] = 0;
				
				
				// Set the copied row's seventh bit
				large[30+8*j] = small[27+j];
				// Set the copied row's parity bit
				if((parity + small[27+j])%2 == 0)
					large[31+8*j] = 1;
				else
					large[31+8*j] = 0;
				
				parity = 0;
			}
			else
			{
				// Set this row's bit
				large[j+i] = small[i];
				// Set the copied row's bit
				large[32+j+i] = small[i];
				parity += small[i];
			}
		}
		return large;
	}
}
